/**
 * This file is part of Wireless TransFer.
 *
 *   Wireless TransFer is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *	
 *   Wireless TransFer is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with Wireless TransFer.  If not, see <http://www.gnu.org/licenses/>.
 *
 *	 Copyright (C) 2011
 *   @author ninjarobirob
 */
package com.wirelesstransfer.client;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Iterator;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;

import android.util.Log;

import com.wirelesstransfer.connection.ITransferData;
import com.wirelesstransfer.connection.ServerActions;

public class Downloader implements Runnable {

	private String TAG = "Client";
	private String PREFIX = "http://";

	private File downloadDir = new File(ServerActions.WTFFILEPATH);
	private File myFile;
	private String fileName;


	private HttpPost post;
	private HttpClient client;
	private ClientConnection clientConnection;

	private Iterator<String> downloads;
	private Map <String, Long> fileMap;

	public volatile boolean isConnected;

	private final int BUFFERSIZE = 65536; 

	private ITransferData receivedData;
	private ApacheClient apacheClient;

	public Downloader(HttpPost post, Iterator <String> downloads, HttpClient client, Map <String, Long> fileMap ) {
		this.post = post;
		this.downloads = downloads;
		this.client = client;
		this.fileMap = fileMap;
		this.apacheClient = ApacheClient.getInstance();
		clientConnection = apacheClient.getConnection();
		receivedData = clientConnection.getTransferData();
	}
	public void run() {
		try {
			isConnected = true;
			InputStream in = null;

			while(isConnected && downloads.hasNext()) {
				Log.v(TAG, "hasnext");

				receivedData.nextFile();
				HttpResponse sendRequestResponse = client.execute(post);
				Log.v(TAG, "send request");

				if(sendRequestResponse.getStatusLine().getStatusCode() == HttpServletResponse.SC_OK){
					sendRequestResponse.getFirstHeader(ServerActions.FILEPATH);
					Log.v(TAG,ServerActions.FILEPATH);
					fileName = downloads.next();
					fileName = filePathToFileName(fileName);

					in = sendRequestResponse.getEntity().getContent();
					long fileSize = fileMap.get(fileName);
					Log.v(TAG, "Size of file" + fileSize);
					receiving(in, fileName, fileSize);



				} else{
					Log.v(TAG, "error " + sendRequestResponse.getStatusLine());
					break;
				}

			}

			receivedData.nextFile();

			Log.v(TAG, "end receive");
			apacheClient.disconnect(clientConnection.getSessionId());
			Log.v(TAG, "end of downloader");

		} catch (ClientProtocolException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalStateException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			reSend();
		}
	}


	/**
	 * A method that receives the streams of data sent by the server and stores it
	 * for the client.
	 * 
	 * @param in
	 * @param fileName
	 * @param fileSize
	 */
	public void receiving(InputStream in, String fileName, long fileSize) {

		try {
			// receive file

			Log.v(TAG, "new Download");

			Log.v(TAG, "file to be dowloaded " + fileName);
			myFile = new File (downloadDir + "/" + fileName);




			if(!myFile.exists()){
				myFile = new File (downloadDir + "/" + fileName);
				myFile.createNewFile();
				Log.v(TAG,"file created");
			}else {
				int number = 0;
				while(myFile.exists()) {
					myFile = new File (downloadDir + "/" + fileName + "(" + number + ")");
					number++;
				}
				myFile.createNewFile();
				Log.v(TAG,"file created");

			}

			byte [] buffer  = new byte [BUFFERSIZE];

			FileOutputStream fos = new FileOutputStream(myFile);

			Log.v(TAG, "download starting");


			int bytesRead = 0;
			while((bytesRead = in.read(buffer)) > -1){
				fos.write(buffer,0,bytesRead);
			}



			fos.flush();
			fos.close();
			in.close();
		} catch (NumberFormatException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalStateException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		Log.v(TAG, "download completed");

	}


	/**
	 * A method that's called when the clients connection 
	 * to the server gets interrupted or fails.
	 */
	public void reSend() {

		InputStream in = null;

		try {
			HttpPost reSendRequest = new HttpPost();

			reSendRequest.setHeader(ServerActions.SESSIONID, clientConnection.getSessionId());
			reSendRequest.setURI(new URI(PREFIX + clientConnection.getIP() + ":" + clientConnection.getPort() + "/" + ServerActions.RESEND));

			HttpResponse reSendRequestResponse = client.execute(reSendRequest);
			in = reSendRequestResponse.getEntity().getContent();
			long fileSize = fileMap.get(fileName);

			if(myFile.exists()) {
				myFile.delete();
			}
			receiving(in, fileName, fileSize);
			Log.v(TAG, "RESEND Size of file" + fileSize);

		} catch (URISyntaxException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClientProtocolException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/**
	 * A help method for extracting the file name from
	 * from the absolute file path received from the server.
	 * @param string
	 * @return the file name as a String
	 */
	private String filePathToFileName(String string) {
		String slash = "/";
		String[] a = string.split(slash);

		String temp = a[a.length -1];
		return temp;
	}


	public boolean disconnected() {
		isConnected = false;
		return isConnected;
	}


}
